# -*- coding: utf-8 -*-

"""
@File    : auto_switch.py
@Author  : xubin
@Time    : 2022/7/20 15:08
@Desc    :
"""
import json
import requests
import pandas as pd
from config import VPN_URLS, DELAY, WARING_MSG_FORMAT
from concurrent.futures import ThreadPoolExecutor
from feapder.utils.log import log
from feapder.utils.tools import retry, send_msg


class AutoSwitch:
    DELAY = DELAY
    WARING_MSG_FORMAT = WARING_MSG_FORMAT
    VPN_URLS = VPN_URLS

    def __init__(self):
        self.waring_flag = False
        self.delay = self.DELAY
        self.speeds = {}
        self.vpn_urls = self.VPN_URLS
        self.error_count = 0
        self.error_message = ['Timeout', 'An error occurred in the delay test']
        self.waring_msg = self.WARING_MSG_FORMAT.format(delay=self.delay)

    def chose_faster_node(self, node_name, url):
        url = f"{url}/proxies/Proxy"
        data = {
            "name": node_name
        }
        data = json.dumps(data)
        response = requests.put(url, data=data, verify=False)
        if response.status_code == 204:
            log.info(f'切换成功,{url.strip("/proxies/Proxy")}当前节点为：{node_name}')

    def get_all_nodes(self, url):
        """返回该vpn的所有节点"""
        url = url + '/proxies'
        try:
            return requests.get(url).json().get('proxies').get('Proxy').get('all')
        except Exception as e:
            print(e)

    def random_choose_node_name(self, data: dict):
        data = [[i, data[i]] for i in data]
        df = pd.DataFrame(data)
        # 获取延迟最低的node_name
        # fast_node = df.sort_values(by=1).iloc[0][0]
        # print(fast_node)

        # 获取所有延迟小于delay的node_name
        fast_nodes = df[df[1] < self.delay]

        # 延迟超出预期
        if fast_nodes.empty:
            log.warning(f'All nodes delayed beyond expectations,expect delay:{self.delay}')
            self.waring_flag = True
            return
        return fast_nodes.sample(1).iloc[0][0]

    def test_speed(self, node_name, url):
        url = f"{url}/proxies/{node_name}/delay"
        params = {
            "timeout": "5000",
            "url": "http://www.gstatic.com/generate_204"
        }
        response = requests.get(url, params=params, verify=False).json()
        if delay := response.get('delay'):
            self.speeds |= {node_name: int(delay)}
        else:
            if response.get('message') in self.error_message:
                self.error_count += 1

    @retry(retry_times=3, interval=0)
    def call_back(self, url):
        if node_name := self.random_choose_node_name(self.speeds):
            self.chose_faster_node(node_name, url)
            self.speeds.clear()
        else:
            log.warning(f'{url} 将发送警报')
            self.waring_msg += f'|\t{url}\t|\n'

    def start(self):
        for url in self.vpn_urls:
            with ThreadPoolExecutor(100) as t:
                all_nodes = self.get_all_nodes(url)

                if not all_nodes:
                    msg = f'Node:{url} may fail'
                    log.warning(msg)
                    send_msg(msg)
                else:
                    for node_name in all_nodes:
                        t.submit(self.test_speed, node_name=node_name, url=url)
            try:
                self.call_back(url)
            except Exception as e:
                log.warning(e)
                self.waring_flag = True
        if self.error_count > 500:
            self.waring_msg += f'Have  {self.error_count} error message:\n' + ' or '.join(self.error_message)
        if self.waring_flag:
            send_msg(msg=self.waring_msg)
        # 重置报警模版
        self.waring_msg = self.WARING_MSG_FORMAT
